package com.rickpan.service;

import com.rickpan.entity.FileInfo;
import com.rickpan.entity.User;
import com.rickpan.repository.FileInfoRepository;
import com.rickpan.repository.UserRepository;
import com.rickpan.storage.StorageService;
import com.rickpan.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 回收站服务
 * 
 * @author RickPan Team
 * @since 2025-01-07
 */
@Service
public class TrashService {
    
    private static final Logger logger = LoggerFactory.getLogger(TrashService.class);
    
    @Autowired
    private FileInfoRepository fileInfoRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private StorageService storageService;
    
    /**
     * 获取回收站文件列表
     * 
     * @param userId 用户ID
     * @param pageable 分页参数
     * @return 已删除文件列表
     */
    public Page<FileInfo> getTrashFiles(Long userId, Pageable pageable) {
        logger.debug("获取用户 {} 的回收站文件列表", userId);
        return fileInfoRepository.findByOwnerIdAndIsDeletedTrue(userId, pageable);
    }
    
    /**
     * 获取回收站统计信息
     * 
     * @param userId 用户ID
     * @return 统计信息
     */
    public TrashStats getTrashStats(Long userId) {
        logger.debug("获取用户 {} 的回收站统计信息", userId);
        
        List<FileInfo> trashFiles = fileInfoRepository.findByOwnerIdAndIsDeletedTrue(userId);
        
        long totalFiles = trashFiles.size();
        long totalSize = trashFiles.stream()
            .filter(file -> !file.getIsDirectory())
            .mapToLong(FileInfo::getFileSize)
            .sum();
        
        // 计算30天内将被自动清理的文件数量
        LocalDateTime cutoffDate = LocalDateTime.now().minusDays(30);
        long expiringSoon = trashFiles.stream()
            .filter(file -> file.getDeletedAt() != null && file.getDeletedAt().isBefore(cutoffDate))
            .count();
        
        return new TrashStats(totalFiles, totalSize, expiringSoon);
    }
    
    /**
     * 还原文件
     * 
     * @param userId 用户ID
     * @param fileIds 文件ID列表
     * @param restoreToRoot 是否还原到根目录
     */
    @Transactional
    public void restoreFiles(Long userId, List<Long> fileIds, boolean restoreToRoot) {
        logger.info("用户 {} 还原文件: fileIds={}, restoreToRoot={}", userId, fileIds, restoreToRoot);
        
        for (Long fileId : fileIds) {
            restoreFile(userId, fileId, restoreToRoot);
        }
    }
    
    /**
     * 还原单个文件
     */
    private void restoreFile(Long userId, Long fileId, boolean restoreToRoot) {
        // 验证文件是否存在且属于当前用户
        Optional<FileInfo> fileOpt = fileInfoRepository.findByIdAndOwnerIdAndIsDeletedTrue(fileId, userId);
        if (fileOpt.isEmpty()) {
            throw new BusinessException("文件不存在或已被还原");
        }
        
        FileInfo fileInfo = fileOpt.get();
        
        // 确定还原位置
        Long targetParentId = null;
        if (!restoreToRoot && fileInfo.getOriginalParentId() != null) {
            // 检查原始父目录是否还存在
            Optional<FileInfo> originalParent = fileInfoRepository
                .findByIdAndOwnerIdAndIsDeletedFalse(fileInfo.getOriginalParentId(), userId);
            if (originalParent.isPresent() && originalParent.get().getIsDirectory()) {
                targetParentId = fileInfo.getOriginalParentId();
            }
        }
        
        // 检查目标位置是否有同名文件
        String originalName = fileInfo.getOriginalName();
        List<FileInfo> existingFiles = fileInfoRepository
            .findByOwnerIdAndParentIdAndOriginalNameAndIsDeletedFalse(userId, targetParentId, originalName);

        if (!existingFiles.isEmpty()) {
            // 生成新的文件名
            originalName = generateUniqueFileName(userId, targetParentId, originalName);
            fileInfo.setOriginalName(originalName);
            fileInfo.setFileName(originalName);
        }
        
        // 计算要恢复的存储空间
        long restoredSize = 0;
        if (!fileInfo.getIsDirectory()) {
            // 文件：直接使用文件大小
            restoredSize = fileInfo.getFileSize();
        } else {
            // 文件夹：计算所有子文件的大小
            restoredSize = calculateRestoredFolderSize(userId, fileId);
        }

        // 检查用户存储配额
        if (restoredSize > 0) {
            checkUserStorageQuota(userId, restoredSize);
        }

        // 还原文件
        fileInfo.setIsDeleted(false);
        fileInfo.setDeletedAt(null);
        fileInfo.setParentId(targetParentId);
        fileInfo.setUpdatedAt(LocalDateTime.now());

        fileInfoRepository.save(fileInfo);

        // 如果是文件夹，递归还原子文件
        if (fileInfo.getIsDirectory()) {
            restoreChildrenRecursively(userId, fileId);
        }

        // 更新用户存储使用量（增加）
        if (restoredSize > 0) {
            updateUserStorageUsage(userId, restoredSize);
            logger.info("恢复存储空间: userId={}, restoredSize={} bytes", userId, restoredSize);
        }

        logger.info("文件还原成功: fileId={}, targetParentId={}, newName={}, restoredSize={}",
                   fileId, targetParentId, originalName, restoredSize);
    }
    
    /**
     * 彻底删除文件
     * 
     * @param userId 用户ID
     * @param fileIds 文件ID列表
     */
    @Transactional
    public void permanentDeleteFiles(Long userId, List<Long> fileIds) {
        logger.info("用户 {} 彻底删除文件: fileIds={}", userId, fileIds);
        
        for (Long fileId : fileIds) {
            permanentDeleteFile(userId, fileId);
        }
    }
    
    /**
     * 彻底删除单个文件
     */
    private void permanentDeleteFile(Long userId, Long fileId) {
        // 验证文件是否存在且属于当前用户
        Optional<FileInfo> fileOpt = fileInfoRepository.findByIdAndOwnerIdAndIsDeletedTrue(fileId, userId);
        if (fileOpt.isEmpty()) {
            throw new BusinessException("文件不存在或未被删除");
        }
        
        FileInfo fileInfo = fileOpt.get();
        
        try {
            // 从存储服务删除物理文件
            if (!fileInfo.getIsDirectory()) {
                boolean deleted = storageService.deleteFile(fileInfo.getFilePath());
                if (!deleted) {
                    logger.warn("从存储服务删除文件失败: filePath={}", fileInfo.getFilePath());
                }
            }
            
            // 如果是文件夹，递归删除子文件
            if (fileInfo.getIsDirectory()) {
                permanentDeleteChildrenRecursively(userId, fileId);
            }
            
            // 从数据库删除记录
            fileInfoRepository.delete(fileInfo);
            
            logger.info("文件彻底删除成功: fileId={}, filePath={}", fileId, fileInfo.getFilePath());
            
        } catch (Exception e) {
            logger.error("彻底删除文件失败: fileId={}", fileId, e);
            throw new BusinessException("彻底删除文件失败: " + e.getMessage());
        }
    }
    
    /**
     * 递归彻底删除子文件
     */
    private void permanentDeleteChildrenRecursively(Long userId, Long parentId) {
        List<FileInfo> children = fileInfoRepository.findByOwnerIdAndParentIdAndIsDeletedTrue(userId, parentId);
        
        for (FileInfo child : children) {
            if (child.getIsDirectory()) {
                permanentDeleteChildrenRecursively(userId, child.getId());
            } else {
                // 删除物理文件
                storageService.deleteFile(child.getFilePath());
            }
            
            // 删除数据库记录
            fileInfoRepository.delete(child);
        }
    }
    
    /**
     * 清空回收站
     * 
     * @param userId 用户ID
     */
    @Transactional
    public void emptyTrash(Long userId) {
        logger.info("用户 {} 清空回收站", userId);
        
        List<FileInfo> trashFiles = fileInfoRepository.findByOwnerIdAndIsDeletedTrue(userId);
        
        for (FileInfo file : trashFiles) {
            try {
                // 删除物理文件
                if (!file.getIsDirectory()) {
                    storageService.deleteFile(file.getFilePath());
                }
                
                // 删除数据库记录
                fileInfoRepository.delete(file);
                
            } catch (Exception e) {
                logger.error("清空回收站时删除文件失败: fileId={}", file.getId(), e);
            }
        }
        
        logger.info("回收站清空完成，共删除 {} 个文件", trashFiles.size());
    }
    
    /**
     * 检查用户存储配额
     */
    private void checkUserStorageQuota(Long userId, Long fileSize) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));

        if (user.getStorageUsed() + fileSize > user.getStorageQuota()) {
            throw new BusinessException("存储空间不足，无法还原文件");
        }
    }

    /**
     * 更新用户存储使用量
     */
    private void updateUserStorageUsage(Long userId, Long fileSize) {
        // 简化处理：直接在当前事务中更新，使用重试机制处理并发
        int maxRetries = 3;
        Exception lastException = null;

        for (int i = 0; i < maxRetries; i++) {
            try {
                int updatedRows = userRepository.updateStorageUsed(userId, fileSize);
                if (updatedRows > 0) {
                    logger.debug("存储使用量更新成功: userId={}, fileSize={}, retry={}", userId, fileSize, i);
                    return; // 成功
                }

                // 检查用户是否存在
                if (!userRepository.existsById(userId)) {
                    throw new BusinessException("用户不存在: " + userId);
                }

                // 用户存在但更新失败，可能是并发问题，继续重试
                lastException = new RuntimeException("更新行数为0，可能存在并发冲突");

                if (i < maxRetries - 1) {
                    try {
                        // 短暂延迟后重试
                        Thread.sleep(50 * (i + 1)); // 50ms, 100ms, 150ms
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new BusinessException("更新被中断");
                    }
                }

            } catch (Exception e) {
                lastException = e;
                logger.warn("存储使用量更新失败，重试 {}/{}: userId={}, fileSize={}, error={}",
                           i + 1, maxRetries, userId, fileSize, e.getMessage());

                if (i < maxRetries - 1) {
                    try {
                        Thread.sleep(50 * (i + 1));
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        throw new BusinessException("更新被中断");
                    }
                }
            }
        }

        // 所有重试都失败，记录警告但不阻止文件还原
        String errorMsg = lastException != null ? lastException.getMessage() : "未知错误";
        logger.warn("存储使用量更新失败，但文件还原继续: userId={}, fileSize={}, error={}",
                   userId, fileSize, errorMsg);
        // 注意：这里不抛异常，允许文件还原成功，存储配额稍后可以通过定时任务修复
    }

    /**
     * 计算要恢复的文件夹大小（包括所有已删除的子文件）
     */
    private long calculateRestoredFolderSize(Long userId, Long folderId) {
        long totalSize = 0;
        List<FileInfo> children = fileInfoRepository.findByOwnerIdAndParentIdAndIsDeletedTrue(userId, folderId);

        for (FileInfo child : children) {
            if (!child.getIsDirectory()) {
                // 文件：累加文件大小
                totalSize += child.getFileSize();
            } else {
                // 子文件夹：递归计算
                totalSize += calculateRestoredFolderSize(userId, child.getId());
            }
        }

        return totalSize;
    }

    /**
     * 递归还原子文件
     */
    private void restoreChildrenRecursively(Long userId, Long parentId) {
        List<FileInfo> children = fileInfoRepository.findByOwnerIdAndParentIdAndIsDeletedTrue(userId, parentId);

        for (FileInfo child : children) {
            child.setIsDeleted(false);
            child.setDeletedAt(null);
            child.setUpdatedAt(LocalDateTime.now());
            fileInfoRepository.save(child);

            if (child.getIsDirectory()) {
                restoreChildrenRecursively(userId, child.getId());
            }
        }
    }

    /**
     * 生成唯一文件名
     */
    private String generateUniqueFileName(Long userId, Long parentId, String originalName) {
        String baseName = originalName;
        String extension = "";

        int lastDotIndex = originalName.lastIndexOf('.');
        if (lastDotIndex > 0) {
            baseName = originalName.substring(0, lastDotIndex);
            extension = originalName.substring(lastDotIndex);
        }

        int counter = 1;
        String newName = originalName;

        while (!fileInfoRepository.findByOwnerIdAndParentIdAndOriginalNameAndIsDeletedFalse(
                userId, parentId, newName).isEmpty()) {
            newName = baseName + " (" + counter + ")" + extension;
            counter++;
        }

        return newName;
    }
    
    /**
     * 回收站统计信息
     */
    public static class TrashStats {
        private final long totalFiles;
        private final long totalSize;
        private final long expiringSoon;
        
        public TrashStats(long totalFiles, long totalSize, long expiringSoon) {
            this.totalFiles = totalFiles;
            this.totalSize = totalSize;
            this.expiringSoon = expiringSoon;
        }
        
        public long getTotalFiles() { return totalFiles; }
        public long getTotalSize() { return totalSize; }
        public long getExpiringSoon() { return expiringSoon; }
    }
}
